package org.example.nettyrpc;

import org.example.nettyrpc.common.IpPortTuple;

public abstract class EndpointBase {
    private final RpcHost rpcHost;
    private final RpcGuest[] rpcGuests;

    public EndpointBase(IpPortTuple myIpPort, IpPortTuple[] otherIpPorts) {
        if (myIpPort != null) {
            this.rpcHost = new RpcHost(this, myIpPort);
        } else {
            this.rpcHost = null;
        }

        rpcGuests = new RpcGuest[otherIpPorts.length];
        for (int i = 0; i < otherIpPorts.length; i++) {
            rpcGuests[i] = new RpcGuest(this, otherIpPorts[i]);
        }
    }

    public void bootHostAndGuestRpc() throws InterruptedException {
        if (this.rpcHost!=null){
            Thread st = new Thread(() -> {
                try {
                    rpcHost.run();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            st.setDaemon(true);
            st.start();
            rpcHost.waitForConnected();
        }

        for (RpcGuest rpcGuest : rpcGuests) {
            Thread t = new Thread(rpcGuest::run);
            t.setDaemon(true);
            t.start();
        }

        Thread.sleep(2000); // 等待，尽量让连接建立
    }

    public Object remoteCall(int serverNum, String methodName, Object... parameters) throws InterruptedException {
        rpcGuests[serverNum].waitForConnected();
        return rpcGuests[serverNum].remoteCall(methodName, parameters);
    }

    // define some methods to invoke through reflection
}
